Table of Contents

  • 1  Preamble
    • 1.1  Imports
    • 1.2  Lists
    • 1.3  Formatting functions
    • 1.4  API call functions
  • 2  Data aquisition
    • 2.1  Fetch online data
    • 2.2  Format data
    • 2.3  Save data
  • 3  Check changes
    • 3.1  Load latest file
    • 3.2  Generate changelog
  • 4  Data visualisation
    • 4.1  Full data
    • 4.2  Card types
    • 4.3  Monsters
      • 4.3.1  Attributes
      • 4.3.2  Primary types
        • 4.3.2.1  Has effect discrimination
        • 4.3.2.2  Is pendulum discrimination
        • 4.3.2.3  By attribute
      • 4.3.3  Secondary types
        • 4.3.3.1  By attribute
        • 4.3.3.2  By secondary type
      • 4.3.4  Monster types
        • 4.3.4.1  By Attribute
        • 4.3.4.2  By primary type
        • 4.3.4.3  By secondary type
      • 4.3.5  Effect type
      • 4.3.6  ATK
      • 4.3.7  DEF
      • 4.3.8  Level/Rank
        • 4.3.8.1  ATK statistics
        • 4.3.8.2  DEF statistics
      • 4.3.9  Pendulum scale
        • 4.3.9.1  ATK statistics
        • 4.3.9.2  DEF statistics
        • 4.3.9.3  Level/Rank statistics
      • 4.3.10  Link
        • 4.3.10.1  ATK statistics
      • 4.3.11  Link Arrows
        • 4.3.11.1  By combination
        • 4.3.11.2  By unique
        • 4.3.11.3  By link
    • 4.4  Spell & Trap
      • 4.4.1  Properties
      • 4.4.2  Effect type
        • 4.4.2.1  Spell & Trap discrimination
    • 4.5  Archseries
      • 4.5.1  By card type
      • 4.5.2  By primary type
      • 4.5.3  By secondary type
      • 4.5.4  By monster type
      • 4.5.5  By property
    • 4.6  Artworks
      • 4.6.1  By card type
      • 4.6.2  By primary type
    • 4.7  Errata
      • 4.7.1  By card type
      • 4.7.2  By primary type
      • 4.7.3  By artwork
    • 4.8  TCG & OCG status
      • 4.8.1  TGC status
        • 4.8.1.1  By card type
        • 4.8.1.2  By monster type
        • 4.8.1.3  By archseries
      • 4.8.2  OCG status
        • 4.8.2.1  By card type
        • 4.8.2.2  By monster type
        • 4.8.2.3  By archseries
      • 4.8.3  TCG vs. OCG status
  • 5  HTML export
  • 6  Searches

Preamble¶

Imports¶

import glob
import os
import pandas as pd
import numpy as np
import seaborn as sns
%matplotlib inline
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm, Normalize
from matplotlib_venn import venn2
from datetime import datetime
from ast import literal_eval

Lists¶

# Attributes to split monsters query
attributes = ['DIVINE', 'LIGHT', 'DARK', 'WATER', 'EARTH', 'FIRE', 'WIND']

# API variables
api_url = 'https://yugipedia.com/api.php'

# Styling dictionaries
arrows_dict = {'Middle-Left': '\u2190', 'Middle-Right': '\u2192', 'Top-Left': '\u2196', 'Top-Center': '\u2191', 'Top-Right': '\u2197', 'Bottom-Left': '\u2199', 'Bottom-Center': '\u2193', 'Bottom-Right': '\u2198'}
card_colors = {'Effect Monster': '#FF8B53', 'Normal Monster': '#FDE68A', 'Ritual Monster': '#9DB5CC', 'Fusion Monster': '#A086B7', 'Synchro Monster': '#CCCCCC', 'Xyz Monster': '#000000', 'Link Monster': '#00008B', 'Pendulum Monster': 'r', 'Monster Card': '#FF8B53', 'Spell Card': '#1D9E74', 'Trap Card': '#BC5A84', 'Monster Token': '#C0C0C0', 'FIRE': '#fd1b1b', 'WATER': '#03a9e6', 'EARTH': '#060d0a', 'WIND': '#77bb58', 'DARK': '#745ea5', 'LIGHT': '#9d8047', 'DIVINE': '#7e6537', 'Level': '#f1a41f'}

Formatting functions¶

def extract_results(df):
    df = pd.DataFrame(df['query']['results']).transpose()
    df = pd.DataFrame(df['printouts'].values.tolist())
    return df

def extract_artwork(row):
    result = tuple()
    if 'Category:OCG/TCG cards with alternate artworks' in row:
        result += ('Alternate',)
    if 'Category:OCG/TCG cards with edited artworks' in row:
        result += ('Edited',)
    if result == tuple():
        return np.nan
    else:
        return result

def concat_errata(row):
    result = tuple()
    if row['Name errata']:
        result += ('Name',)
    if row['Type errata']:
        result += ('Type',)
    if result == tuple():
        return np.nan
    else:
        return result 
    
def format_df(input_df, input_errata_df):
    df = pd.DataFrame()
    if 'Name' in input_df.columns:
        df['Name'] = input_df['Name'].dropna().apply(lambda x: x[0])
    if 'Password' in input_df.columns:
        df['Password'] = input_df['Password'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'Card type' in input_df.columns:
        df['Card type'] = input_df['Card type'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Property' in input_df.columns:
        df['Property'] = input_df['Property'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'Primary type' in input_df.columns:
        df['Primary type'] = input_df['Primary type'].dropna().apply(lambda x: [i['fulltext'] for i in x] if len(x)>0 else []).apply(lambda y: list(filter(lambda z: z != 'Pendulum Monster', y)) if len(y)>0 else []).apply(lambda y: list(filter(lambda z: z != 'Effect Monster', y))[0] if len(y)>1 else (y[0] if len(y)>0 else np.nan))
    if 'Secondary type' in input_df.columns:
        df['Secondary type'] = input_df['Secondary type'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Attribute' in input_df.columns:
        df['Attribute'] = input_df['Attribute'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Monster type' in input_df.columns:
        df['Monster type'] = input_df['Monster type'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Level/Rank' in input_df.columns:
        df['Level/Rank'] = input_df['Level/Rank'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'ATK' in input_df.columns:
        df['ATK'] = input_df['ATK'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'DEF' in input_df.columns:
        df['DEF'] = input_df['DEF'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'Pendulum Scale' in input_df.columns:
        df['Pendulum Scale'] = input_df['Pendulum Scale'].dropna().apply(lambda x: str(x[0]) if len(x)>0 else np.nan)
    if 'Link' in input_df.columns:
        df['Link'] = input_df['Link'].dropna().apply(lambda x: str(x[0]) if len(x)>0 else np.nan)
    if 'Link Arrows' in input_df.columns:
        df['Link Arrows'] = input_df['Link Arrows'].dropna().apply(lambda x: tuple([arrows_dict[i] for i in sorted(x)]) if len(x)>0 else np.nan)
    if 'Effect type' in input_df.columns:
        df['Effect type'] = input_df['Effect type'].dropna().apply(lambda x: tuple(sorted([i['fulltext'] for i in x])) if len(x)>0 else np.nan)
    if 'Archseries' in input_df.columns:
        df['Archseries'] = input_df['Archseries'].dropna().apply(lambda x: tuple(sorted(x)) if len(x)>0 else np.nan)
    if 'Category' in input_df.columns:
        df['Artwork'] = input_df['Category'].dropna().apply(lambda x: [i['fulltext'] for i in x] if len(x)>0 else np.nan).apply(extract_artwork)
    # Erratas column
    if input_errata_df is not None and 'Page name' in input_df.columns:
        df['Errata'] = errata_df.merge(input_df['Page name'].dropna().apply(lambda x: x[0]).rename('Name'), right_on = 'Name', left_index = True).apply(concat_errata,axis = 1)
    #################
    if 'TCG status' in input_df.columns:
        df['TCG status'] = input_df['TCG status'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'OCG status' in input_df.columns:
        df['OCG status'] = input_df['OCG status'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Modification date' in input_df.columns:
        df['Modification date'] = input_df['Modification date'].dropna().apply(lambda x: pd.Timestamp(int(x[0]['timestamp']), unit='s').ctime() if len(x)>0 else np.nan)
    
    return df

API call functions¶

def card_query(_password = True, _card_type = True, _property = True, _primary = True, _secondary = True, _attribute = True, _monster_type = True, _stars = True, _atk = True, _def = True, _scale = True, _link = True, _arrows = True, _effect_type = True, _archseries = True, _category = True, _tcg = True, _ocg = True, _date = True, _page_name = True):
    search_string = f'|?English%20name=Name'
    if _password:
        search_string += '|?Password'
    if _card_type:
        search_string += '|?Card%20type'
    if _property:    
        search_string += '|?Property'
    if _primary:
        search_string += '|?Primary%20type'
    if _secondary:
        search_string += '|?Secondary%20type'
    if _attribute:
        search_string += '|?Attribute'
    if _monster_type:
        search_string += '|?Type=Monster%20type'
    if _stars:
        search_string += '|?Stars%20string=Level%2FRank%20'
    if _atk:
        search_string += '|?ATK%20string=ATK'
    if _def:
        search_string += '|?DEF%20string=DEF'
    if _scale:
        search_string += '|?Pendulum%20Scale'
    if _link:
        search_string += '|?Link%20Rating=Link'
    if _arrows:
        search_string += '|?Link%20Arrows'
    if _effect_type:
        search_string += '|?Effect%20type'
    if _archseries:
        search_string += '|?Archseries'
    if _category:
        search_string += '|?category'
    if _tcg:
        search_string += '|?TCG%20status'
    if _ocg:
        search_string += '|?OCG%20status'
    if _date:
        search_string += '|?Modification%20date'
    if _page_name:
        search_string += '|?Page%20name'
    
    return search_string

def fetch_spell(spell_query, step = 5000, limit = 5000):
    print('Downloading Spells')
    spell_df = pd.DataFrame()
    for i in range(int(limit/step)):
        df = pd.read_json(f'{api_url}?action=ask&query=[[Concept:CG%20Spell%20Cards]]{spell_query}|limit%3D{step}|offset={i*step}|order%3Dasc&format=json')
        df = extract_results(df)
        print(f'Iteration {i+1}: {len(df.index)} results')
        spell_df = pd.concat([spell_df, df], ignore_index=True, axis=0)
        if len(df.index)<step:
            break
                
    print(f'- Total\n{len(spell_df.index)} results\n')
    
    return spell_df

def fetch_trap(trap_query, step = 5000, limit = 5000):
    print('Downloading Traps')
    trap_df = pd.DataFrame()
    for i in range(int(limit/step)):    
        df = pd.read_json(f'{api_url}?action=ask&query=[[Concept:CG%20Trap%20Cards]]{trap_query}|limit%3D{step}|offset={i*step}|order%3Dasc&format=json')
        df = extract_results(df)
        print(f'Iteration {i+1}: {len(df.index)} results')
        trap_df = pd.concat([trap_df, df], ignore_index=True, axis=0)
        if len(df.index)<step:
            break
                
    print(f'- Total\n{len(trap_df.index)} results\n')
    
    return trap_df

def fetch_monster(monster_query, step = 5000, limit = 5000):
    print('Downloading Monsters')
    monster_df = pd.DataFrame()
    for att in attributes:
        print(f"- {att}")
        for i in range(int(limit/step)):
            df = pd.read_json(f'{api_url}?action=ask&query=[[Concept:CG%20monsters]][[Attribute::{att}]]{monster_query}|limit%3D{step}|offset={i*step}|order%3Dasc&format=json')
            df = extract_results(df)
            print(f'Iteration {i+1}: {len(df.index)} results')
            monster_df = pd.concat([monster_df, df], ignore_index=True, axis=0)
            if len(df.index)<step:
                break
        
    print(f'- Total\n{len(monster_df.index)} results')
    
    return monster_df

def fetch_name_errata(limit = 1000):
    name_query_df = pd.read_json(f'{api_url}?action=ask&query=[[Category:Cards%20with%20name%20errata]]|limit={limit}|order%3Dasc&format=json')
    name_keys = list(name_query_df['query']['results'].keys())
    return pd.DataFrame(True, index = [i.split(':')[1].strip() for i in name_keys if 'Card Errata:' in i], columns = ['Name errata'])

def fetch_type_errata(limit = 1000):
    type_query_df = pd.read_json(f'{api_url}?action=ask&query=[[Category:Cards%20with%20card%20type%20errata]]|limit={limit}|order%3Dasc&format=json')
    type_keys = list(type_query_df['query']['results'].keys())
    return pd.DataFrame(True, index = [i.split(':')[1].strip() for i in type_keys if 'Card Errata:' in i], columns = ['Type errata'])

Data aquisition¶

Fetch online data¶

monster_query = card_query(_property = False)
st_query = card_query(_primary = False, _secondary = False, _attribute = False, _monster_type = False, _stars = False, _atk = False, _def = False, _scale = False, _link = False, _arrows = False)
# Timestamp
timestamp = pd.Timestamp.now().timestamp()
full_df = pd.DataFrame()

# Fetch Spell
spell_df = fetch_spell(st_query, step = 1000, limit = 3000)
full_df = pd.concat([full_df, spell_df], ignore_index=True, axis=0)

# Fetch Trap
trap_df = fetch_trap(st_query, step = 1000, limit = 3000)
full_df = pd.concat([full_df, trap_df], ignore_index=True, axis=0)
st_df = pd.concat([spell_df, trap_df], ignore_index=True, axis=0)

# Fetch Monster
monster_df = fetch_monster(monster_query, step = 1000, limit = 5000)
full_df = pd.concat([full_df, monster_df], ignore_index=True, axis=0)

# Fetch errata
errata_df = pd.concat([fetch_name_errata(), fetch_type_errata()], axis=1).fillna(False)
Downloading Spells
Iteration 1: 1000 results
Iteration 2: 1000 results
Iteration 3: 341 results
- Total
2341 results

Downloading Traps
Iteration 1: 1000 results
Iteration 2: 792 results
- Total
1792 results

Downloading Monsters
- DIVINE
Iteration 1: 9 results
- LIGHT
Iteration 1: 1000 results
Iteration 2: 610 results
- DARK
Iteration 1: 1000 results
Iteration 2: 1000 results
Iteration 3: 198 results
- WATER
Iteration 1: 824 results
- EARTH
Iteration 1: 1000 results
Iteration 2: 854 results
- FIRE
Iteration 1: 659 results
- WIND
Iteration 1: 757 results
- Total
7911 results

Format data¶

formatted_spell_df = format_df(spell_df, errata_df)
formatted_trap_df = format_df(trap_df, errata_df)
formatted_st_df = format_df(st_df, errata_df)
formatted_monster_df = format_df(monster_df, errata_df)
formatted_full_df = format_df(full_df, errata_df)
print('Data formated')
Data formated

Save data¶

formatted_full_df.to_csv(f'Data/All_cards_{int(timestamp)}.csv', index = False)
print('Data saved')
Data saved

Check changes¶

Load latest file¶

# Get list of files
list_of_files = sorted(glob.glob('Data/All_cards_*.csv'), key=os.path.getctime, reverse=True)
# Get second newest file if exist
if len(list_of_files)>1:
    latest_file = list_of_files[1]
    previous_df = pd.read_csv(latest_file, dtype=object)
    # Correct tuples
    previous_df['Effect type'] = previous_df['Effect type'].dropna().apply(literal_eval)
    previous_df['Link Arrows'] = previous_df['Link Arrows'].dropna().apply(literal_eval)
    previous_df['Archseries'] = previous_df['Archseries'].dropna().apply(literal_eval)
    previous_df['Artwork'] = previous_df['Artwork'].dropna().apply(literal_eval)
    previous_df['Errata'] = previous_df['Errata'].dropna().apply(literal_eval)
    print('File loaded')
else:
    print('No older files')
File loaded

Generate changelog¶

if previous_df is not None:
    changelog = previous_df.merge(formatted_full_df,indicator = True, how='outer').loc[lambda x : x['_merge']!='both'].sort_values('Name', ignore_index=True)
    changelog['_merge'].replace(['left_only','right_only'],['Old', 'New'], inplace = True)
    changelog.rename(columns={"_merge": "Version"}, inplace = True)
    nunique = changelog.groupby('Name').nunique()
    cols_to_drop = nunique[nunique < 2].dropna(axis=1).columns
    changelog = changelog.set_index('Name')[nunique > 1]
    changelog.drop(cols_to_drop, axis=1, inplace = True)
    changelog
else:
    print('No changes')

Data visualisation¶

Full data¶

formatted_full_df
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK ... Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
0 "A" Cell Breeding Device 34541863 Spell Card Continuous Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Trigger Effect,) NaN NaN (Name,) Unlimited Unlimited Sat Nov 6 13:57:15 2021
1 "A" Cell Incubator 64163367 Spell Card Continuous Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Continuous-like Effect, Trigger Effect) NaN NaN NaN Unlimited Unlimited Mon Jun 13 04:27:51 2022
2 "A" Cell Recombination Device 91231901 Spell Card Quick-Play Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Effect, Ignition-like Effect) NaN NaN NaN Unlimited Unlimited Thu Mar 12 22:40:14 2020
3 "A" Cell Scatter Burst 73262676 Spell Card Quick-Play Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Effect,) NaN NaN NaN Unlimited Unlimited Sat Nov 6 13:58:32 2021
4 "Infernoble Arms - Durendal" 37478723 Spell Card Equip Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Condition, Ignition-like Effect, Trigger Effect) (Noble Arms,) NaN NaN Unlimited Unlimited Sat Aug 20 13:52:48 2022
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
12039 Yosenju Shinchu L 65025250 Monster Card NaN Effect Monster NaN WIND Rock 4 0 ... 3 NaN NaN (Continuous Effect, Continuous-like Effect, Tr... (Yosenju,) NaN NaN Unlimited Unlimited Sun Aug 14 11:04:00 2022
12040 Yosenju Shinchu R 91420254 Monster Card NaN Effect Monster NaN WIND Rock 4 0 ... 5 NaN NaN (Continuous Effect, Ignition-like Effect, Trig... (Yosenju,) NaN NaN Unlimited Unlimited Sat Aug 13 12:21:48 2022
12041 Yosenju Tsujik 25244515 Monster Card NaN Effect Monster NaN WIND Beast-Warrior 4 1000 ... NaN NaN NaN (Condition, Ignition Effect, Quick Effect, Tri... (Yosenju,) NaN NaN Unlimited Unlimited Sun Dec 20 18:15:02 2020
12042 ZW - Eagle Claw 29353756 Monster Card NaN Effect Monster NaN WIND Winged Beast 5 2000 ... NaN NaN NaN (Continuous-like Effect, Ignition Effect, Uncl... (ZW -, Zexal) NaN NaN Unlimited Unlimited Thu Jul 8 13:48:07 2021
12043 ZW - Tornado Bringer 81471108 Monster Card NaN Effect Monster NaN WIND Dragon 5 1300 ... NaN NaN NaN (Continuous-like Effect, Ignition Effect, Uncl... (ZW -, Zexal) NaN NaN Unlimited Unlimited Sun Aug 14 11:04:24 2022

12044 rows × 21 columns

Card types¶

formatted_full_df.groupby('Card type').nunique()
Name Password Property Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Card type
Monster Card 7903 7812 0 8 6 7 25 15 82 77 13 6 61 221 976 3 3 7 7 7856
Spell Card 2339 2329 6 0 0 0 0 0 0 0 0 0 0 114 390 3 3 5 6 2327
Trap Card 1792 1778 3 0 0 0 0 0 0 0 0 0 0 94 322 3 3 5 6 1786
card_type_colors = [card_colors[i] for i in formatted_full_df['Card type'].value_counts().index]
formatted_full_df['Card type'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=0, color = card_type_colors)
plt.show()

Monsters¶

Attributes¶

print('Total number of attributes:', formatted_monster_df['Attribute'].nunique())
Total number of attributes: 7
formatted_monster_df.drop(columns=['Card type']).groupby('Attribute').nunique()
Name Password Primary type Secondary type Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Attribute
DARK 2195 2173 7 6 23 14 70 63 12 6 39 152 442 3 3 6 7 2191
DIVINE 6 0 1 0 2 2 3 3 0 0 0 6 3 1 3 2 2 9
EARTH 1852 1838 7 6 23 12 71 59 11 4 29 124 322 3 3 5 6 1845
FIRE 659 657 8 6 22 12 43 40 8 4 22 83 183 3 3 3 6 657
LIGHT 1610 1573 7 6 23 14 58 50 10 5 30 130 381 3 3 7 6 1602
WATER 824 820 7 6 22 11 56 41 9 4 16 91 201 3 3 6 6 824
WIND 757 751 7 6 23 12 46 38 11 4 14 104 211 3 3 5 6 752
attribute_colors = [card_colors[i] for i in formatted_full_df['Attribute'].value_counts().index]
formatted_monster_df['Attribute'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=0, color = attribute_colors)
plt.show()

Primary types¶

print('Total number of primary types:', formatted_monster_df['Primary type'].nunique())
Total number of primary types: 8
formatted_monster_df.drop(columns=['Card type']).groupby('Primary type').nunique()

Has effect discrimination¶

has_effect = formatted_monster_df['Primary type'].where(formatted_monster_df['Effect type'].notna()).value_counts().rename('Effect')
no_effect = formatted_monster_df['Primary type'].where(formatted_monster_df['Effect type'].isna()).value_counts().rename('No Effect')
effect = pd.concat([has_effect,no_effect], axis=1)
effect
Effect No Effect
Effect Monster 5371.0 1
Xyz Monster 484.0 2
Synchro Monster 399.0 3
Link Monster 359.0 5
Fusion Monster 358.0 62
Ritual Monster 101.0 16
Normal Monster 34.0 712
Monster Token NaN 1
monster_type_colors = {'No Effect': card_colors['Normal Monster'], 'Effect': [card_colors[i] for i in effect.index]}
effect.plot.bar(figsize = (18,6), stacked = True, grid = True, rot=0,  legend=True, color = monster_type_colors)
plt.show()

Normal monster can have effect if it is pendulum

Is pendulum discrimination¶

not_pendulum = formatted_monster_df['Primary type'].where(formatted_monster_df['Pendulum Scale'].isna()).value_counts().rename('Not Pendulum')
is_pendulum = formatted_monster_df['Primary type'].where(formatted_monster_df['Pendulum Scale'].notna()).value_counts().rename('Pendulum')
pendulum = pd.concat([not_pendulum,is_pendulum], axis=1)
pendulum
Not Pendulum Pendulum
Effect Monster 5111 261.0
Normal Monster 708 38.0
Xyz Monster 479 7.0
Fusion Monster 411 9.0
Synchro Monster 397 5.0
Link Monster 364 NaN
Ritual Monster 116 1.0
Monster Token 1 NaN
monster_type_colors_b = {'Pendulum': card_colors['Pendulum Monster'], 'Not Pendulum': [card_colors[i] for i in pendulum.index]}
pendulum.plot.bar(figsize = (18,6), stacked = True, grid = True, rot=0, color = monster_type_colors_b, legend=True)
plt.show()

By attribute¶

primmary_crosstab = pd.crosstab(formatted_full_df['Primary type'],formatted_full_df['Attribute'])
primmary_crosstab
Attribute DARK DIVINE EARTH FIRE LIGHT WATER WIND
Primary type
Effect Monster 1478 6 1287 446 1086 545 524
Fusion Monster 144 0 79 34 96 34 33
Link Monster 117 0 74 33 86 29 25
Monster Token 0 0 0 1 0 0 0
Normal Monster 186 0 250 52 82 109 67
Ritual Monster 35 0 17 7 33 19 6
Synchro Monster 105 0 67 50 74 33 73
Xyz Monster 133 0 80 36 153 55 29
plt.figure(figsize = (16,10))
sns.heatmap(primmary_crosstab.T, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

Secondary types¶

print('Total number of secondary types:', formatted_monster_df['Secondary type'].nunique())
Total number of secondary types: 6
formatted_monster_df.drop(columns=['Card type', 'Link', 'Link Arrows']).groupby('Secondary type').nunique()
Name Password Primary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Effect type Archseries Artwork Errata TCG status OCG status Modification date
Secondary type
Flip monster 183 182 2 6 19 12 38 33 1 20 44 2 3 3 4 183
Gemini monster 45 45 1 6 18 8 17 19 0 6 13 0 3 1 1 45
Spirit monster 37 37 2 6 13 9 22 20 2 7 4 1 1 2 2 37
Toon monster 17 17 1 6 7 5 12 15 0 8 13 1 2 1 2 17
Tuner monster 461 461 5 6 23 9 32 32 7 56 131 3 3 3 5 460
Union monster 37 37 1 6 9 8 17 14 0 6 9 1 2 1 1 37
secondary_type_colors = card_colors['Effect Monster']
formatted_monster_df['Secondary type'].value_counts().plot.bar(figsize = (18,6), stacked = True, grid = True, rot=0, color = secondary_type_colors, legend=True)
plt.show()

By attribute¶

secondary_crosstab = pd.crosstab(formatted_full_df['Secondary type'],formatted_full_df['Attribute'])
secondary_crosstab
Attribute DARK EARTH FIRE LIGHT WATER WIND
Secondary type
Flip monster 51 61 10 31 13 17
Gemini monster 11 8 8 6 8 4
Spirit monster 5 6 6 4 6 10
Toon monster 7 5 1 2 1 1
Tuner monster 119 91 42 91 50 68
Union monster 6 9 3 12 4 3
plt.figure(figsize = (8,6))
sns.heatmap(secondary_crosstab, annot=True, fmt="g", cmap='viridis', square=True)
plt.show()

By secondary type¶

secondary_crosstab_b = pd.crosstab(formatted_full_df['Primary type'],formatted_full_df['Secondary type'], margins = True)
secondary_crosstab_b
Secondary type Flip monster Gemini monster Spirit monster Toon monster Tuner monster Union monster All
Primary type
Effect Monster 182 45 35 17 415 37 731
Fusion Monster 0 0 0 0 3 0 3
Normal Monster 0 0 0 0 12 0 12
Ritual Monster 1 0 2 0 1 0 4
Synchro Monster 0 0 0 0 30 0 30
All 183 45 37 17 461 37 780
plt.figure(figsize = (10,7))
sns.heatmap(secondary_crosstab_b, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

Monster types¶

print('Total number of monster types:', formatted_monster_df['Monster type'].nunique())
Total number of monster types: 25
formatted_monster_df.drop(columns=['Card type']).groupby('Monster type').nunique()
Name Password Primary type Secondary type Attribute Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Monster type
Aqua 254 252 7 6 6 10 50 33 3 2 3 51 64 2 3 3 3 254
Beast 375 367 7 4 6 10 48 38 7 2 7 59 82 3 3 4 6 376
Beast-Warrior 236 232 7 3 6 10 36 29 6 3 7 57 47 3 3 4 5 235
Creator God 1 0 1 0 1 1 1 1 0 0 0 1 1 0 0 0 1 1
Cyberse 246 244 7 1 6 11 30 29 1 6 38 45 34 2 2 3 5 246
Dinosaur 121 120 6 1 6 10 35 30 4 2 3 35 24 1 2 3 4 121
Divine-Beast 5 0 1 0 1 1 3 3 0 0 0 5 2 1 3 2 2 8
Dragon 654 646 7 6 6 13 52 48 9 5 19 109 184 2 3 6 6 651
Fairy 505 497 7 5 6 12 43 38 8 4 12 78 109 3 3 6 6 501
Fiend 756 746 7 6 6 13 60 45 12 5 14 106 146 3 3 5 5 755
Fish 121 121 7 2 5 10 34 28 1 1 1 30 20 2 2 2 3 121
Insect 236 235 7 3 6 12 44 33 2 3 6 55 39 2 2 2 3 236
Machine 910 900 7 5 6 12 62 55 9 4 22 110 165 3 3 5 7 904
Plant 230 228 6 4 6 9 37 30 5 4 9 38 38 2 2 3 4 230
Psychic 174 173 6 2 6 11 35 31 5 2 3 41 40 1 2 4 5 174
Pyro 121 120 7 5 5 11 34 29 0 1 1 36 33 1 3 1 3 121
Reptile 171 170 6 3 6 11 37 30 3 2 3 46 35 0 2 4 4 171
Rock 246 244 7 4 6 11 43 39 4 3 4 59 72 1 3 5 5 245
Sea Serpent 82 82 6 3 6 10 28 26 1 2 2 32 28 2 3 2 2 82
Spellcaster 671 662 7 5 6 12 49 40 10 5 12 100 146 3 3 5 6 667
Thunder 127 125 6 4 6 10 35 29 1 2 4 36 32 1 2 3 3 127
Warrior 1022 1015 7 6 6 13 60 41 6 3 15 92 214 3 3 6 7 1020
Winged Beast 312 309 7 5 6 10 39 29 4 4 6 61 65 2 3 4 4 312
Wyrm 85 85 6 1 6 11 26 24 3 4 6 32 19 1 1 4 2 85
Zombie 242 239 7 5 6 12 38 37 1 3 5 51 35 2 3 1 3 241
monster_type_colors = card_colors['Monster Card']
formatted_monster_df['Monster type'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=45, color = monster_type_colors)
plt.show()

By Attribute¶

monster_crosstab = pd.crosstab(formatted_full_df['Monster type'],formatted_full_df['Attribute'], dropna=False)
monster_crosstab
Attribute DARK DIVINE EARTH FIRE LIGHT WATER WIND
Monster type
Aqua 9 0 6 10 4 219 6
Beast 37 0 212 16 72 14 25
Beast-Warrior 37 0 82 53 33 16 15
Creator God 0 1 0 0 0 0 0
Cyberse 63 0 36 44 63 28 12
Dinosaur 11 0 59 32 5 8 6
Divine-Beast 0 8 0 0 0 0 0
Dragon 251 0 47 48 167 28 113
Fairy 55 0 60 15 324 26 25
Fiend 570 0 33 46 70 23 16
Fish 2 0 2 0 1 114 2
Insect 37 0 127 6 20 4 42
Machine 221 0 308 50 167 48 116
Plant 42 0 118 11 22 24 13
Psychic 23 0 36 17 44 12 42
Pyro 2 0 6 106 4 0 3
Reptile 39 0 34 15 45 34 4
Rock 16 0 198 5 15 5 7
Sea Serpent 3 0 1 1 2 71 4
Spellcaster 280 0 53 28 187 62 62
Thunder 13 0 10 5 76 4 19
Warrior 202 0 363 100 245 53 60
Winged Beast 109 0 7 16 15 12 153
Wyrm 15 0 18 10 22 12 8
Zombie 161 0 38 25 7 7 4
plt.figure(figsize = (20,5))
sns.heatmap(monster_crosstab.T, annot=True, fmt="g", cmap='viridis', square=True)
plt.show()

By primary type¶

monster_crosstab_b = pd.crosstab(formatted_full_df['Monster type'],formatted_full_df['Primary type'], dropna=False)
monster_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Monster Token Normal Monster Ritual Monster Synchro Monster Xyz Monster
Monster type
Aqua 153 11 3 0 59 8 3 17
Beast 270 17 9 0 54 1 14 11
Beast-Warrior 162 11 9 0 21 2 8 23
Creator God 1 0 0 0 0 0 0 0
Cyberse 122 4 93 0 7 6 5 9
Dinosaur 86 7 3 0 18 0 4 3
Divine-Beast 5 0 0 0 0 0 0 0
Dragon 345 62 33 0 46 15 93 60
Fairy 360 20 24 0 36 17 17 31
Fiend 531 46 27 0 79 15 20 40
Fish 87 5 1 0 17 1 7 3
Insect 174 2 9 0 29 1 7 14
Machine 632 46 38 0 67 4 60 63
Plant 161 6 15 0 25 0 7 16
Psychic 117 11 5 0 9 0 19 13
Pyro 84 8 1 1 18 0 5 4
Reptile 140 1 3 0 19 0 5 3
Rock 168 18 4 0 28 7 5 16
Sea Serpent 55 2 2 0 8 0 5 10
Spellcaster 509 25 26 0 55 16 16 25
Thunder 96 8 5 0 11 0 5 2
Warrior 671 93 29 0 80 14 54 82
Winged Beast 227 8 9 0 27 4 15 22
Wyrm 53 2 9 0 3 0 10 8
Zombie 163 7 7 0 30 6 18 11
plt.figure(figsize = (20,5))
sns.heatmap(monster_crosstab_b.T, annot=True, fmt="g", cmap='viridis', square=True, norm = LogNorm())
plt.show()

By secondary type¶

monster_crosstab_c = pd.crosstab(formatted_full_df['Monster type'],formatted_full_df['Secondary type'], dropna=False)
monster_crosstab_c
Secondary type Flip monster Gemini monster Spirit monster Toon monster Tuner monster Union monster
Monster type
Aqua 4 4 1 1 10 3
Beast 15 1 2 0 22 0
Beast-Warrior 1 0 1 0 9 0
Cyberse 0 0 0 0 6 0
Dinosaur 0 0 0 0 7 0
Dragon 1 6 1 3 42 4
Fairy 8 2 7 0 20 5
Fiend 27 4 2 1 41 1
Fish 0 1 0 0 7 0
Insect 20 2 0 0 11 0
Machine 10 1 0 4 80 18
Plant 4 1 0 0 20 1
Psychic 3 0 0 0 22 0
Pyro 4 2 2 0 8 1
Reptile 18 1 0 0 7 0
Rock 11 1 2 0 3 0
Sea Serpent 1 1 0 0 9 0
Spellcaster 33 3 4 4 39 0
Thunder 3 1 1 0 7 0
Warrior 11 9 5 3 30 3
Winged Beast 5 2 7 1 30 0
Wyrm 0 0 0 0 9 0
Zombie 4 3 2 0 22 1
plt.figure(figsize = (20,5))
sns.heatmap(monster_crosstab_c.T, annot=True, fmt="g", cmap='viridis', square=True, norm = LogNorm())
plt.show()

Effect type¶

print('Total number of effect types:', formatted_monster_df['Effect type'].explode().nunique())
Total number of effect types: 14
formatted_monster_df[formatted_monster_df['Effect type'].notna()].drop(columns=['Card type']).explode('Effect type').groupby('Effect type').nunique()
Name Password Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Archseries Artwork Errata TCG status OCG status Modification date
Effect type
Activation condition 1 1 1 0 1 1 1 1 1 1 0 0 1 0 0 1 1 1
Condition 2992 2953 7 6 7 25 14 63 63 13 5 53 628 3 3 4 6 2973
Continuous Effect 2123 2115 6 5 7 24 14 59 52 12 6 48 550 3 3 4 4 2121
Continuous-like Effect 233 233 6 3 6 21 11 42 36 13 1 2 72 2 3 3 2 233
Flip effect 169 168 1 1 6 19 12 38 33 1 0 0 42 2 3 3 4 169
Ignition Effect 2563 2553 6 6 7 24 13 66 61 12 5 42 629 3 3 4 6 2551
Ignition-like Effect 214 208 6 2 6 20 12 35 32 13 1 1 73 1 3 3 4 214
Lingering effect 16 16 2 1 6 11 7 11 13 0 2 2 9 0 0 2 1 16
Maintenance cost 44 44 3 0 6 12 8 21 18 2 1 1 8 0 1 1 1 44
Quick Effect 992 991 6 4 6 23 13 50 47 8 5 28 383 3 3 5 4 991
Quick-like Effect 4 4 1 0 1 1 1 3 2 0 0 0 1 0 0 1 1 4
Summoning condition 901 864 6 4 7 25 13 52 51 8 5 6 312 3 3 6 5 897
Trigger Effect 4250 4240 7 6 7 24 14 66 62 13 5 49 751 3 3 4 6 4225
Unclassified effect 801 795 6 5 7 25 13 49 45 9 5 12 270 3 3 3 4 799
monster_effect_colors = card_colors['Effect Monster']
formatted_monster_df['Effect type'].explode('Effect type').value_counts().plot.bar(figsize = (18,6), grid = True, color = monster_effect_colors)
plt.show()

ATK¶

print('Total number of ATK values:', formatted_monster_df['ATK'].nunique())
Total number of ATK values: 82
formatted_monster_df.drop(columns=['Card type']).groupby('ATK').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type Level/Rank DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
ATK
0 608 584 8 5 6 23 13 35 9 5 15 91 232 3 3 5 5 607
50 2 2 1 0 2 2 1 2 0 0 0 2 2 0 0 1 1 2
100 216 216 5 3 6 20 11 27 8 2 2 48 106 2 3 2 2 216
150 1 1 1 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1
200 117 116 6 5 6 20 7 21 4 1 2 34 67 2 3 2 4 117
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4500 12 12 3 0 3 6 4 4 0 0 0 10 9 1 1 1 1 12
4600 2 2 1 0 2 1 1 1 0 0 0 2 1 0 0 1 1 2
5000 9 9 5 0 3 4 2 4 0 1 1 8 6 1 1 1 1 9
? 83 75 6 1 7 20 15 8 2 1 1 34 36 2 3 4 4 84
X000 1 0 0 0 1 1 1 1 0 0 0 0 1 0 0 1 1 1

82 rows × 18 columns

atk_colors = card_colors['Monster Card']
formatted_monster_df['DEF'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, color = atk_colors)
plt.show()

DEF¶

print('Total number of DEF values:', formatted_monster_df['DEF'].nunique())
Total number of DEF values: 77
formatted_monster_df.drop(columns=['Card type']).groupby('DEF').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type Level/Rank ATK Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
DEF
0 763 737 7 6 6 23 14 45 10 0 0 103 258 3 3 5 5 760
50 1 1 1 0 1 1 1 1 0 0 0 1 1 0 0 1 1 1
100 207 206 5 4 6 19 10 24 8 0 0 46 94 2 3 3 3 206
200 248 245 5 5 6 23 10 31 5 0 0 47 107 3 3 3 5 248
250 8 8 2 1 4 5 2 4 0 0 0 5 3 0 1 1 1 8
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4500 2 2 2 0 2 2 1 1 0 0 0 2 1 0 0 1 1 2
4800 1 1 1 0 1 1 1 1 0 0 0 1 1 0 0 1 1 1
5000 5 5 2 0 3 3 2 2 0 0 0 4 3 1 1 1 1 5
? 56 49 5 1 7 17 14 2 1 0 0 25 25 2 3 4 4 57
X000 1 0 0 0 1 1 1 1 0 0 0 0 1 0 0 1 1 1

77 rows × 18 columns

def_colors = card_colors['Monster Card']
formatted_monster_df['DEF'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, color = def_colors)
plt.show()

Level/Rank¶

formatted_monster_df.drop(columns=['Card type', 'Link', 'Link Arrows']).groupby('Level/Rank').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type ATK DEF Pendulum Scale Effect type Archseries Artwork Errata TCG status OCG status Modification date
Level/Rank
0 6 6 2 0 2 2 3 3 0 5 3 0 0 2 2 6
1 627 601 7 5 6 23 22 29 10 80 227 3 3 4 5 625
2 668 660 6 5 6 23 29 30 7 72 211 3 3 4 6 667
3 1140 1136 6 5 6 23 41 36 9 92 289 3 3 4 7 1140
4 2318 2312 6 6 6 23 54 47 9 133 501 3 3 4 7 2310
5 591 591 6 6 6 23 46 38 8 83 233 3 3 3 4 591
6 600 597 6 6 6 23 38 38 9 92 232 3 3 5 6 601
7 462 457 6 6 6 23 37 35 9 99 220 3 3 4 6 463
8 663 646 6 5 6 23 42 41 8 110 297 3 3 5 5 664
9 139 138 5 2 6 21 30 27 1 54 85 1 3 4 4 139
10 243 231 5 2 7 22 32 33 6 75 146 2 3 3 4 246
11 31 30 6 2 6 13 16 17 1 22 23 0 1 3 3 31
12 49 48 5 1 6 12 12 16 2 31 36 1 2 2 2 49
13 1 1 1 0 1 1 1 1 0 1 1 0 0 1 1 1
? 1 0 1 0 1 1 1 1 0 0 0 0 0 0 1 1
stars_colors = card_colors['Level']
formatted_monster_df['Level/Rank'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, rot=0, color= stars_colors)
plt.show()

ATK statistics¶

formatted_monster_df[['Level/Rank','ATK']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Level/Rank').describe()
ATK
count mean std min 25% 50% 75% max
Level/Rank
0 5.0 600.000000 1341.640786 0.0 0.0 0.0 0.0 3000.0
1 617.0 239.789303 352.151718 0.0 0.0 100.0 300.0 2500.0
2 666.0 584.159159 408.923728 0.0 300.0 500.0 800.0 2400.0
3 1137.0 959.586631 485.294765 0.0 600.0 1000.0 1300.0 3000.0
4 2306.0 1418.226366 540.573507 0.0 1200.0 1500.0 1800.0 3000.0
5 588.0 1765.765306 638.460344 0.0 1500.0 1900.0 2200.0 4000.0
6 597.0 2012.814070 615.827964 0.0 1900.0 2200.0 2400.0 4000.0
7 458.0 2290.502183 610.943569 0.0 2200.0 2500.0 2600.0 3300.0
8 655.0 2550.305344 708.170899 0.0 2500.0 2800.0 3000.0 4500.0
9 136.0 2594.485294 851.005349 0.0 2500.0 2800.0 3000.0 4500.0
10 223.0 2823.542601 1222.294588 0.0 2800.0 3000.0 3500.0 5000.0
11 30.0 2990.000000 1093.113238 0.0 3000.0 3350.0 3500.0 4000.0
12 45.0 3355.555556 1429.964328 0.0 3000.0 4000.0 4000.0 5000.0

DEF statistics¶

formatted_monster_df[['Level/Rank','DEF']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Level/Rank').describe()
DEF
count mean std min 25% 50% 75% max
Level/Rank
0 5.0 400.000000 894.427191 0.0 0.0 0.0 0.0 2000.0
1 619.0 337.883683 519.434793 0.0 0.0 100.0 400.0 2500.0
2 667.0 659.370315 554.951687 0.0 200.0 500.0 900.0 2400.0
3 1137.0 952.858399 570.271595 0.0 600.0 900.0 1300.0 3000.0
4 2308.0 1170.116984 606.011951 0.0 800.0 1200.0 1600.0 3000.0
5 589.0 1421.731749 673.303655 0.0 1000.0 1500.0 1900.0 3000.0
6 597.0 1560.016750 709.357990 0.0 1200.0 1700.0 2000.0 3000.0
7 460.0 1881.521739 652.359443 0.0 1600.0 2000.0 2300.0 3300.0
8 662.0 1975.528701 846.576772 0.0 1600.0 2100.0 2500.0 4000.0
9 136.0 2306.250000 799.431221 0.0 2000.0 2500.0 3000.0 3700.0
10 232.0 2232.543103 1284.231371 0.0 1900.0 2500.0 3000.0 5000.0
11 30.0 2661.666667 1169.415071 0.0 2125.0 3000.0 3400.0 4000.0
12 46.0 2852.173913 1672.089728 0.0 2000.0 3350.0 4000.0 5000.0

Pendulum scale¶

formatted_monster_df.drop(columns=['Card type', 'Link', 'Link Arrows']).groupby('Pendulum Scale').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Effect type Archseries Artwork Errata TCG status OCG status Modification date
Pendulum Scale
0 10 10 2 1 5 7 6 5 5 8 8 1 0 1 1 10
1 67 64 5 2 6 10 11 28 26 37 38 0 1 3 5 67
2 36 36 2 1 6 11 6 17 22 21 15 0 2 3 2 36
3 36 36 2 1 6 15 8 22 15 23 17 0 0 1 1 36
4 32 32 5 0 5 8 8 18 16 25 16 1 1 1 1 32
5 34 34 2 1 6 12 7 23 21 20 16 0 1 3 3 34
6 15 15 1 1 4 7 6 11 11 11 9 0 0 1 1 15
7 27 27 2 1 6 14 6 19 17 14 16 0 2 1 1 27
8 39 39 5 1 6 9 8 19 18 23 21 0 0 1 2 39
9 8 8 2 1 3 3 5 3 2 5 3 0 0 1 1 8
10 14 11 5 0 6 6 5 6 8 11 8 0 0 2 2 14
12 2 2 1 0 1 2 2 2 2 2 2 0 0 1 1 2
13 1 1 1 0 1 1 1 1 1 1 1 0 0 1 1 1
scales_colors = card_colors['Pendulum Monster']
formatted_monster_df['Pendulum Scale'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, rot=0, color = scales_colors)
plt.show()

ATK statistics¶

formatted_monster_df[['Pendulum Scale','ATK']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Pendulum Scale').describe()
ATK
count mean std min 25% 50% 75% max
Pendulum Scale
0 10.0 1390.000000 1317.784336 0.0 0.0 1450.0 2500.0 3000.0
1 66.0 1751.515152 1053.381723 0.0 1000.0 1800.0 2500.0 4000.0
2 36.0 1423.611111 688.734462 100.0 800.0 1500.0 2000.0 2500.0
3 36.0 1437.500000 845.354955 0.0 600.0 1725.0 2025.0 2600.0
4 32.0 1787.500000 1011.785391 0.0 1100.0 2000.0 2550.0 3000.0
5 34.0 1339.705882 808.831875 0.0 850.0 1325.0 1800.0 3450.0
6 15.0 1320.000000 707.308783 100.0 950.0 1500.0 1800.0 2400.0
7 27.0 1279.629630 787.920737 0.0 700.0 1400.0 1750.0 3000.0
8 39.0 1225.641026 968.644726 0.0 300.0 1200.0 2000.0 3300.0
9 8.0 2150.000000 730.948503 1000.0 2050.0 2400.0 2500.0 2800.0
10 14.0 1678.571429 1376.829452 0.0 125.0 2500.0 2875.0 3000.0
12 1.0 100.000000 NaN 100.0 100.0 100.0 100.0 100.0
13 1.0 0.000000 NaN 0.0 0.0 0.0 0.0 0.0

DEF statistics¶

formatted_monster_df[['Pendulum Scale','DEF']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Pendulum Scale').describe()
DEF
count mean std min 25% 50% 75% max
Pendulum Scale
0 10.0 1200.000000 1273.664878 0.0 0.0 750.0 2500.0 3000.0
1 67.0 1571.641791 940.310389 0.0 950.0 1700.0 2350.0 4000.0
2 36.0 1338.888889 728.316171 0.0 875.0 1200.0 1825.0 2700.0
3 36.0 1165.277778 788.834533 0.0 575.0 1200.0 1800.0 3000.0
4 32.0 1534.375000 830.316448 0.0 1000.0 1600.0 2075.0 2800.0
5 34.0 1136.764706 822.625953 0.0 550.0 1000.0 1575.0 3000.0
6 15.0 1226.666667 711.604492 400.0 600.0 1100.0 1700.0 2600.0
7 27.0 1312.962963 830.383669 0.0 700.0 1300.0 2000.0 2700.0
8 39.0 1015.384615 789.916205 0.0 350.0 1000.0 1700.0 2700.0
9 8.0 1225.000000 636.396103 1000.0 1000.0 1000.0 1000.0 2800.0
10 14.0 1850.000000 1124.380171 0.0 750.0 2500.0 2575.0 3000.0
12 1.0 100.000000 NaN 100.0 100.0 100.0 100.0 100.0
13 1.0 0.000000 NaN 0.0 0.0 0.0 0.0 0.0

Level/Rank statistics¶

formatted_monster_df[['Pendulum Scale','Level/Rank']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Pendulum Scale').describe()
Level/Rank
count mean std min 25% 50% 75% max
Pendulum Scale
0 10.0 6.100000 3.348300 1.0 3.75 7.0 8.00 10.0
1 67.0 5.955224 2.427324 1.0 4.00 6.0 8.00 12.0
2 36.0 4.416667 1.380993 1.0 3.75 4.0 5.00 7.0
3 36.0 4.444444 1.731134 1.0 4.00 4.0 5.00 10.0
4 32.0 5.562500 2.154328 1.0 4.00 6.0 7.00 8.0
5 34.0 4.176471 1.961301 1.0 3.00 4.0 4.00 11.0
6 15.0 3.933333 1.579632 1.0 3.00 4.0 4.50 8.0
7 27.0 4.185185 1.641693 2.0 3.00 4.0 5.00 10.0
8 39.0 3.923077 2.355113 1.0 2.00 4.0 6.00 10.0
9 8.0 5.625000 1.302470 4.0 5.00 5.0 6.25 8.0
10 14.0 6.714286 2.812843 1.0 7.00 7.0 7.75 10.0
12 2.0 6.500000 7.778175 1.0 3.75 6.5 9.25 12.0
13 1.0 7.000000 NaN 7.0 7.00 7.0 7.00 7.0

Link¶

formatted_monster_df.drop(columns=['Card type', 'Primary type', 'Secondary type','Level/Rank','DEF','Pendulum Scale']).groupby('Link').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Attribute Monster type ATK Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Link
1 47 47 6 11 10 8 17 26 1 0 3 3 47
2 183 183 6 23 23 19 31 101 1 2 3 4 183
3 81 81 6 16 17 17 25 46 2 1 2 3 81
4 44 41 6 16 12 13 21 24 2 0 3 5 44
5 8 5 2 5 4 3 5 4 0 0 2 2 8
6 1 1 1 1 1 1 1 1 0 0 1 1 1
link_colors = card_colors['Link Monster']
formatted_monster_df['Link'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, rot=0, color = link_colors)
plt.show()

ATK statistics¶

formatted_monster_df[['Link','ATK']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Link').describe()
ATK
count mean std min 25% 50% 75% max
Link
1 47.0 736.170213 482.937358 0.0 400.0 800.0 1000.0 1500.0
2 183.0 1399.726776 509.349328 0.0 1100.0 1500.0 1800.0 2300.0
3 81.0 2258.641975 659.487970 0.0 2200.0 2400.0 2500.0 4000.0
4 43.0 2660.465116 653.976676 0.0 2500.0 2800.0 3000.0 3300.0
5 8.0 3250.000000 755.928946 2500.0 3000.0 3000.0 3125.0 5000.0
6 1.0 0.000000 NaN 0.0 0.0 0.0 0.0 0.0

Link Arrows¶

By combination¶

print('Total number of link arrow combinations:', formatted_monster_df['Link Arrows'].nunique())
Total number of link arrow combinations: 61
formatted_monster_df.drop(columns=['Card type', 'Primary type', 'Level/Rank', 'Pendulum Scale', 'Link', 'Secondary type', 'DEF']).groupby('Link Arrows').nunique()
Name Password Attribute Monster type ATK Effect type Archseries Artwork Errata TCG status OCG status Modification date
Link Arrows
(←,) 5 5 2 3 2 4 4 0 0 3 2 5
(←, ↑) 4 4 2 3 4 3 2 0 0 1 1 4
(←, →) 18 18 6 8 11 8 9 0 0 2 2 18
(←, →, ↑) 7 7 3 5 6 6 5 0 0 1 1 7
(↑,) 10 10 5 5 6 9 5 0 0 1 1 10
... ... ... ... ... ... ... ... ... ... ... ... ...
(↙, ↘, ←, ↖) 1 1 1 1 1 1 1 0 0 1 1 1
(↙, ↘, ↑) 22 22 6 11 11 11 15 1 1 2 2 22
(↙, ↘, →) 2 2 2 2 2 2 2 0 0 1 1 2
(↙, ↘, ↖) 2 2 2 2 2 2 0 0 0 1 2 2
(↙, ↘, ↖, ↗) 1 1 1 1 1 1 1 0 0 1 1 1

61 rows × 12 columns

arrows_colors = card_colors['Link Monster']
formatted_monster_df['Link Arrows'].value_counts().plot.bar(figsize = (18,6), logy=True, grid = True, color = arrows_colors)
plt.show()

By unique¶

formatted_monster_df[formatted_monster_df['Link Arrows'].notna()].drop(columns=['Card type', 'Primary type', 'Level/Rank', 'Pendulum Scale', 'Secondary type', 'DEF']).explode('Link Arrows').groupby('Link Arrows').nunique()
Name Password Attribute Monster type ATK Link Effect type Archseries Artwork Errata TCG status OCG status Modification date
Link Arrows
← 113 107 6 21 29 6 34 45 2 0 4 3 113
↑ 114 111 6 19 27 6 31 44 2 1 3 5 114
→ 99 93 6 19 27 6 29 40 2 0 3 3 99
↓ 156 150 6 20 31 6 41 68 3 0 3 5 156
↖ 10 10 5 5 9 4 6 5 1 0 1 3 10
↗ 15 15 5 7 10 5 7 7 0 0 1 2 15
↘ 184 181 6 22 32 6 35 102 3 2 4 5 184
↙ 187 184 6 22 33 6 37 103 3 2 4 5 187
arrows_colors_b = card_colors['Link Monster']
formatted_monster_df['Link Arrows'].explode('Link Arrows').value_counts().plot.bar(figsize = (18,6), grid = True, color = arrows_colors_b)
plt.show()

By link¶

arrow_per_link = formatted_monster_df[['Link Arrows','Link']].explode('Link Arrows').dropna()
arrow_crosstab = pd.crosstab(arrow_per_link['Link Arrows'],arrow_per_link['Link'])
arrow_crosstab
Link 1 2 3 4 5 6
Link Arrows
← 5 47 23 30 7 1
↑ 10 28 43 28 4 1
→ 2 33 24 31 8 1
↓ 18 59 41 32 5 1
↖ 1 2 5 2 0 0
↗ 3 5 3 3 1 0
↘ 3 94 53 25 8 1
↙ 5 98 51 25 7 1
plt.figure(figsize = (10,6))
sns.heatmap(arrow_crosstab.T, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

Spell & Trap¶

Properties¶

print('Total number of properties:', formatted_st_df['Property'].nunique())
Total number of properties: 9
formatted_st_df.drop(columns=['Card type']).groupby('Property').nunique()
Name Password Effect type Archseries Artwork Errata TCG status OCG status Modification date
Property
Continuous Spell Card 413 411 53 156 3 3 5 5 411
Continuous Trap Card 487 479 62 160 2 3 4 3 487
Counter Trap Card 154 152 19 58 2 2 2 3 154
Equip Spell Card 262 262 37 74 1 3 2 2 262
Field Spell Card 269 266 35 142 2 3 5 5 270
Normal Spell Card 904 902 43 225 3 3 4 6 905
Normal Trap Card 1151 1147 48 236 3 2 4 6 1146
Quick-Play Spell Card 417 414 34 137 3 3 3 4 417
Ritual Spell Card 74 74 8 24 2 2 1 2 74
st_colors = [card_colors[i] for i in formatted_full_df[['Card type','Property']].value_counts().index.get_level_values(0)]
formatted_st_df['Property'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=45, color = st_colors)
plt.show()

Effect type¶

print('Total number of effect types:', formatted_st_df['Effect type'].explode().nunique())
Total number of effect types: 14
formatted_st_df.explode('Effect type').groupby('Effect type').nunique()
Name Password Card type Property Archseries Artwork Errata TCG status OCG status Modification date
Effect type
Activation condition 831 824 2 8 170 3 3 4 5 830
Condition 1631 1618 2 9 366 3 3 5 5 1619
Continuous Effect 21 21 2 6 12 0 2 1 1 21
Continuous-like Effect 889 882 2 7 233 3 3 5 4 889
Cost 452 450 2 7 111 3 3 4 4 452
Effect 2886 2868 2 9 422 3 3 5 6 2872
Ignition Effect 2 2 2 2 2 0 0 1 1 2
Ignition-like Effect 425 424 1 6 177 1 2 4 5 423
Lingering effect 94 94 2 6 41 2 2 3 4 94
Maintenance cost 22 22 2 5 7 1 1 3 3 22
Quick Effect 9 9 2 3 4 0 0 1 1 9
Quick-like Effect 329 325 2 4 146 2 1 3 5 329
Trigger Effect 827 823 2 9 254 2 3 3 5 822
Unclassified effect 83 83 2 9 48 1 0 1 2 82

Spell & Trap discrimination¶

spell = formatted_spell_df['Effect type'].explode('Effect type').value_counts().rename('Spell Card')
trap = formatted_trap_df['Effect type'].explode('Effect type').value_counts().rename('Trap Card')
st_diff = pd.concat([spell, trap], axis = 1)
st_diff
Spell Card Trap Card
Effect 1499 1388.0
Condition 1106 526.0
Continuous-like Effect 610 280.0
Trigger Effect 553 274.0
Ignition-like Effect 425 NaN
Activation condition 244 587.0
Cost 241 211.0
Unclassified effect 63 20.0
Lingering effect 56 38.0
Maintenance cost 11 11.0
Continuous Effect 7 14.0
Quick Effect 4 5.0
Quick-like Effect 3 326.0
Ignition Effect 1 1.0
st_diff_colors = {'Spell Card': card_colors['Spell Card'], 'Trap Card': card_colors['Trap Card']}
st_diff.plot.bar(figsize = (18,6), stacked = True, grid = True, rot=45, color = st_diff_colors)
plt.show()

Archseries¶

exploded_archseries = formatted_full_df.explode('Archseries')
print('Total number of Archseries:', exploded_archseries['Archseries'].nunique())
Total number of Archseries: 705
exploded_archseries.groupby('Archseries').nunique()
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Artwork Errata TCG status OCG status Modification date
Archseries
"C" 8 8 1 0 2 0 1 1 7 8 8 0 0 0 6 0 1 2 1 8
-Eyes Dragon 72 71 1 0 7 2 6 3 10 16 13 6 1 1 44 1 3 2 3 71
/Assault Mode 7 7 1 0 1 0 5 6 5 6 6 0 0 0 5 0 0 1 1 7
@Ignister 18 18 1 0 6 1 6 1 7 10 9 0 3 4 9 0 0 1 1 18
A-to-Z 16 16 1 0 3 1 1 1 4 13 12 0 0 0 5 2 3 1 2 16
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
sphinx 10 10 2 1 1 0 2 2 4 8 5 0 0 0 9 0 0 1 1 10
sprout 2 2 1 0 1 0 1 1 1 1 1 0 0 0 2 0 0 1 1 2
tellarknight 21 21 2 3 2 0 2 3 2 16 14 2 0 0 11 0 0 2 2 21
with Chain 4 4 1 1 0 0 0 0 0 0 0 0 0 0 4 1 0 1 1 4
with Eyes of Blue 8 8 2 2 1 1 1 1 1 3 4 0 0 0 6 0 1 1 1 8

705 rows × 20 columns

exploded_archseries['Archseries'].value_counts().plot.barh(figsize = (10,200), grid = True)
plt.show()

By card type¶

archseries_crosstab = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Card type'], margins = True)
archseries_crosstab
Card type Monster Card Spell Card Trap Card All
Archseries
"C" 8 0 0 8
-Eyes Dragon 72 0 0 72
/Assault Mode 7 0 0 7
@Ignister 18 0 0 18
A-to-Z 16 0 0 16
... ... ... ... ...
sprout 2 0 0 2
tellarknight 17 4 0 21
with Chain 0 0 4 4
with Eyes of Blue 5 3 0 8
All 7213 1332 885 9430

706 rows × 4 columns

By primary type¶

archseries_crosstab_b = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Primary type'], margins = True)
archseries_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Monster Token Normal Monster Ritual Monster Synchro Monster Xyz Monster All
Archseries
"C" 7 0 0 0 1 0 0 0 8
-Eyes Dragon 31 11 1 0 3 4 5 17 72
/Assault Mode 7 0 0 0 0 0 0 0 7
@Ignister 10 1 4 0 0 1 1 1 18
A-to-Z 6 8 0 0 2 0 0 0 16
... ... ... ... ... ... ... ... ... ...
sphinx 9 0 0 0 0 0 0 0 9
sprout 2 0 0 0 0 0 0 0 2
tellarknight 12 0 0 0 0 0 0 5 17
with Eyes of Blue 5 0 0 0 0 0 0 0 5
All 4632 527 329 1 243 118 430 929 7209

644 rows × 9 columns

By secondary type¶

archseries_crosstab_c = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Secondary type'], margins = True)
archseries_crosstab_c
Secondary type Flip monster Gemini monster Spirit monster Toon monster Tuner monster Union monster All
Archseries
-Eyes Dragon 0 2 0 2 0 0 4
@Ignister 0 0 0 0 1 0 1
A-to-Z 0 0 0 0 0 6 6
Adamancipator 0 0 0 0 3 0 3
Alien 1 1 0 0 1 0 3
... ... ... ... ... ... ... ...
itsu 0 0 0 0 0 2 2
lswarm 2 0 0 0 0 0 2
roid 0 0 0 0 9 0 9
with Eyes of Blue 0 0 0 0 5 0 5
All 125 28 13 36 412 18 632

195 rows × 7 columns

By monster type¶

archseries_crosstab_d = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Monster type'], margins = True)
archseries_crosstab_d
Monster type Aqua Beast Beast-Warrior Creator God Cyberse Dinosaur Divine-Beast Dragon Fairy Fiend ... Reptile Rock Sea Serpent Spellcaster Thunder Warrior Winged Beast Wyrm Zombie All
Archseries
"C" 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 8
-Eyes Dragon 0 0 0 0 0 0 0 67 0 0 ... 0 0 0 0 0 0 0 0 3 72
/Assault Mode 0 0 0 0 0 0 0 2 0 0 ... 0 0 0 1 0 1 0 0 1 7
@Ignister 0 0 0 0 18 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 18
A-to-Z 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 16
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
sphinx 0 3 0 0 0 0 0 0 0 0 ... 0 6 0 0 0 0 0 0 0 9
sprout 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 2
tellarknight 0 0 0 0 0 0 0 0 0 1 ... 0 0 0 0 0 15 0 1 0 17
with Eyes of Blue 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 5 0 0 0 0 0 5
All 193 286 183 2 149 81 12 717 442 690 ... 138 213 71 575 94 1236 267 75 158 7213

644 rows × 26 columns

By property¶

archseries_crosstab_e = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Property'], margins = True)
archseries_crosstab_e
Property Continuous Spell Card Continuous Trap Card Counter Trap Card Equip Spell Card Field Spell Card Normal Spell Card Normal Trap Card Quick-Play Spell Card Ritual Spell Card All
Archseries
A.I. 1 3 0 0 1 4 1 2 1 13
Abyss Actor 0 0 0 0 0 0 2 0 0 2
Abyss Script 1 0 0 0 0 4 0 1 0 6
Abyss- 0 1 0 3 0 0 3 0 0 7
Adamancipator 0 0 1 0 1 2 1 0 0 5
... ... ... ... ... ... ... ... ... ... ...
sphinx 0 1 0 0 0 0 0 0 0 1
tellarknight 0 0 0 1 1 0 0 2 0 4
with Chain 0 0 0 0 0 0 4 0 0 4
with Eyes of Blue 1 0 0 0 0 0 0 2 0 3
All 238 286 72 130 176 499 527 253 36 2217

394 rows × 10 columns

Artworks¶

print('Total number of cards with edited or alternate artworks:', formatted_full_df['Artwork'].count())
Total number of cards with edited or alternate artworks: 421
formatted_full_df[['Name','Password','TCG status','OCG status','Artwork']][formatted_full_df['Artwork'].notna()]
Name Password TCG status OCG status Artwork
51 Alluring Mirror Split 92881099 Unlimited Unlimited (Alternate, Edited)
60 Amazoness Spellcaster 81325903 Unlimited Unlimited (Edited,)
69 Ancient Gear Castle 92001300 Unlimited Unlimited (Edited,)
115 Arrivalrivals 29508346 Unlimited Unlimited (Alternate, Edited)
134 Axe of Despair 40619825 Unlimited Unlimited (Edited,)
... ... ... ... ... ...
11864 Soitsu 60246171 Unlimited Unlimited (Edited,)
11915 Stardust Dragon 44508094 Unlimited Unlimited (Alternate,)
11923 Storming Wynn 29013526 Unlimited Unlimited (Alternate, Edited)
11950 Thousand Dragon 41462083 Unlimited Unlimited (Alternate,)
11952 Toon Harpie Lady 64116319 Unlimited Unlimited (Edited,)

421 rows × 5 columns

artwork_value_counts = formatted_full_df['Artwork'].value_counts()
plt.figure(figsize=(20,8))
venn2(subsets = (artwork_value_counts[('Alternate',)], artwork_value_counts[('Edited',)],artwork_value_counts[('Alternate','Edited')]), set_labels = ('Alternate artwork', 'Edited artwork'))
plt.show()

By card type¶

artwork_crosstab = pd.crosstab(formatted_full_df['Artwork'], formatted_full_df['Card type'])
artwork_crosstab
Card type Monster Card Spell Card Trap Card
Artwork
(Alternate,) 79 4 6
(Alternate, Edited) 80 18 19
(Edited,) 110 62 43

By primary type¶

artwork_crosstab_b = pd.crosstab(formatted_full_df['Artwork'], formatted_full_df['Primary type'])
artwork_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Normal Monster Ritual Monster Synchro Monster Xyz Monster
Artwork
(Alternate,) 35 11 6 20 0 3 4
(Alternate, Edited) 39 6 7 20 4 0 4
(Edited,) 78 6 1 20 2 2 1

More granularity is unnecessary

Errata¶

print('Total number of cards with name or type errata:', formatted_full_df['Errata'].count())
Total number of cards with name or type errata: 1129
formatted_full_df[['Name','Password','TCG status','OCG status','Errata']][formatted_full_df['Errata'].notna()]
Name Password TCG status OCG status Errata
0 "A" Cell Breeding Device 34541863 Unlimited Unlimited (Name,)
9 7 Completed 86198326 Unlimited Unlimited (Type,)
10 The A. Forces 00403847 Unlimited Unlimited (Type,)
19 Abyss Playhouse - Fantastic Theater 77297908 Unlimited Unlimited (Name,)
43 Advanced Heraldry Art 61314842 Unlimited Unlimited (Name,)
... ... ... ... ... ...
12013 Winged Dragon, Guardian of the Fortress #1 87796900 Unlimited Unlimited (Name,)
12014 Winged Dragon, Guardian of the Fortress #2 57405307 Unlimited Unlimited (Name,)
12016 Winged Sage Falcos 87523462 Unlimited Unlimited (Name,)
12023 Wynn the Wind Charmer 37744402 Unlimited Unlimited (Name,)
12024 Wynn the Wind Charmer, Verdant 30674956 Unlimited Unlimited (Name,)

1129 rows × 5 columns

errata_value_counts = formatted_full_df['Errata'].value_counts()
plt.figure(figsize=(20,8))
venn2(subsets = (errata_value_counts[('Name',)], errata_value_counts[('Type',)],errata_value_counts[('Name','Type')]), set_labels = ('Name Errata', 'Type errata'))
plt.show()

By card type¶

errata_crosstab = pd.crosstab(formatted_full_df['Errata'], formatted_full_df['Card type'])
errata_crosstab
Card type Monster Card Spell Card Trap Card
Errata
(Name,) 312 57 50
(Name, Type) 73 21 2
(Type,) 396 209 9

By primary type¶

errata_crosstab_b = pd.crosstab(formatted_full_df['Errata'], formatted_full_df['Primary type'])
errata_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Normal Monster Ritual Monster Synchro Monster Xyz Monster
Errata
(Name,) 196 46 4 50 3 9 3
(Name, Type) 39 10 0 17 2 5 0
(Type,) 270 22 2 61 2 24 15

More granularity is unnecessary

By artwork¶

errata_crosstab_c = pd.crosstab(formatted_full_df['Artwork'], formatted_full_df['Errata'])
errata_crosstab_c
Errata (Name,) (Name, Type) (Type,)
Artwork
(Alternate,) 8 15 21
(Alternate, Edited) 9 6 13
(Edited,) 15 7 38

TCG & OCG status¶

TGC status¶

print('Total number of TCG status:', formatted_full_df['TCG status'].nunique())
Total number of TCG status: 7
formatted_full_df.groupby('TCG status', dropna=False).nunique()
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata OCG status Modification date
TCG status
Forbidden 99 99 3 7 5 2 6 19 12 27 21 2 4 10 46 53 2 3 4 99
Illegal 38 0 3 3 5 0 6 14 5 11 12 2 2 2 6 7 0 1 1 38
Legal 20 0 1 0 1 0 5 11 5 6 7 0 0 0 0 13 2 1 1 20
Limited 81 81 3 7 6 3 6 15 9 20 20 3 2 2 42 40 3 3 4 81
Not yet released 2 1 1 0 2 0 1 1 2 2 2 0 0 0 1 1 0 0 1 2
Semi-Limited 9 9 3 4 2 0 3 3 1 3 3 0 0 0 8 8 1 1 3 9
Unlimited 11308 11305 3 9 7 6 7 24 14 80 75 13 6 60 341 1110 3 3 5 11196
NaN 485 425 3 9 8 3 7 23 12 54 39 6 4 8 93 107 1 1 4 483
formatted_full_df['TCG status'].value_counts(dropna = False).plot.bar(figsize = (18,6), logy=True, grid = True, rot=45)
plt.show()

By card type¶

# Remove unlimited
tcg_crosstab = pd.crosstab(formatted_full_df['Card type'], formatted_full_df['TCG status']).drop(['Unlimited'], axis=1)
tcg_crosstab
TCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited
Card type
Monster Card 64 35 20 42 2 3
Spell Card 26 2 0 34 0 5
Trap Card 9 1 0 5 0 1
plt.figure(figsize = (12,6))
sns.heatmap(tcg_crosstab, annot=True, fmt="g", cmap='viridis', norm=LogNorm())
plt.show()

By monster type¶

# Remove unlimited
tcg_crosstab_b = pd.crosstab(formatted_full_df['Monster type'], formatted_full_df['TCG status']).drop(['Unlimited'], axis=1)
tcg_crosstab_b
TCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited
Monster type
Aqua 1 0 2 0 0 0
Beast 0 3 1 2 0 0
Beast-Warrior 2 3 0 2 0 0
Cyberse 2 0 0 1 0 0
Dinosaur 0 0 1 2 0 0
Divine-Beast 0 3 0 0 0 0
Dragon 10 3 1 7 2 0
Fairy 3 4 3 1 0 1
Fiend 5 2 4 3 0 0
Fish 1 0 0 0 0 0
Insect 2 0 0 0 0 0
Machine 6 4 3 6 0 0
Plant 6 1 0 0 0 0
Psychic 2 1 0 1 0 0
Pyro 0 0 0 0 0 0
Reptile 1 0 1 1 0 0
Rock 3 1 1 3 0 0
Sea Serpent 1 0 0 0 0 0
Spellcaster 7 5 1 9 0 0
Thunder 1 1 0 0 0 0
Warrior 4 2 2 2 0 1
Winged Beast 3 2 0 1 0 0
Wyrm 4 0 0 1 0 1
Zombie 0 0 0 0 0 0
plt.figure(figsize = (20,5))
sns.heatmap(tcg_crosstab_b.T, annot=True, fmt="g", cmap='viridis', square = True, norm=LogNorm())
plt.show()

By archseries¶

# Remove unlimited
tcg_crosstab_c = pd.crosstab(exploded_archseries['Archseries'].where(exploded_archseries['OCG status']!='Unlimited'), exploded_archseries['TCG status'], margins = True)
tcg_crosstab_c
TCG status Forbidden Illegal Legal Limited Semi-Limited Unlimited All
Archseries
-Eyes Dragon 1 0 0 0 0 0 1
A-to-Z 0 0 0 0 0 1 1
Abyss- 0 0 0 0 0 1 1
Adventurer Token (series) 0 0 0 0 0 2 2
Amazoness 0 0 0 0 0 1 1
... ... ... ... ... ... ... ...
Zexal 1 0 0 0 0 0 1
Zoodiac 3 0 0 1 0 0 4
roid 0 0 0 1 0 0 1
tellarknight 1 0 0 0 0 0 1
All 68 40 16 29 6 83 242

123 rows × 7 columns

OCG status¶

print('Total number of OCG status:', formatted_full_df['OCG status'].nunique())
Total number of OCG status: 7
formatted_full_df.groupby('OCG status', dropna=False).nunique()
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status Modification date
OCG status
Forbidden 89 89 3 6 5 4 6 19 11 28 21 3 4 7 39 44 2 3 3 89
Illegal 32 1 3 2 6 1 6 12 8 14 15 2 2 2 8 8 0 1 1 32
Legal 39 0 1 0 2 0 6 17 7 8 8 0 0 0 0 24 2 1 1 39
Limited 65 65 3 6 6 2 6 13 9 17 18 3 3 5 33 36 2 3 4 65
Not yet released 51 39 3 8 6 1 6 14 11 22 18 1 3 4 26 11 0 0 1 51
Semi-Limited 19 19 3 5 1 1 2 4 3 4 4 0 0 0 12 12 0 2 4 19
Unlimited 11707 11683 3 9 7 6 7 25 14 81 76 13 6 59 349 1132 3 3 5 11596
NaN 36 23 3 5 6 1 5 14 7 12 12 1 1 1 18 7 0 0 3 36
formatted_full_df['OCG status'].value_counts(dropna = False).plot.bar(figsize = (18,6), logy=True, grid = True, rot=45)
plt.show()

By card type¶

# Remove unlimited
ocg_crosstab = pd.crosstab(formatted_full_df['Card type'], formatted_full_df['OCG status']).drop(['Unlimited'], axis=1)
ocg_crosstab
OCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited
Card type
Monster Card 56 30 39 37 33 4
Spell Card 22 1 0 26 9 14
Trap Card 11 1 0 2 9 1
plt.figure(figsize = (12,6))
sns.heatmap(ocg_crosstab, annot=True, fmt="g", cmap='viridis', norm=LogNorm())
plt.show()

By monster type¶

# Remove unlimited
ocg_crosstab_b = pd.crosstab(formatted_full_df['Monster type'], formatted_full_df['OCG status']).drop(['Unlimited'], axis=1)
ocg_crosstab_b
OCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited
Monster type
Aqua 2 0 2 0 0 0
Beast 1 2 4 0 1 1
Beast-Warrior 3 2 0 1 0 1
Creator God 0 0 0 0 0 0
Cyberse 2 0 2 1 3 0
Dinosaur 0 0 1 1 1 0
Divine-Beast 0 3 0 0 0 0
Dragon 10 3 1 4 3 0
Fairy 2 3 4 1 2 0
Fiend 6 1 7 0 2 0
Fish 1 0 0 0 1 0
Insect 1 0 0 0 11 0
Machine 4 3 6 8 1 1
Plant 5 0 1 1 0 0
Psychic 1 1 0 3 1 0
Pyro 0 0 1 1 0 0
Reptile 1 0 1 0 1 0
Rock 1 1 1 2 0 0
Sea Serpent 1 0 0 0 0 0
Spellcaster 7 7 1 10 2 0
Thunder 0 0 1 2 0 0
Warrior 4 3 3 2 3 1
Winged Beast 2 1 1 0 0 0
Wyrm 2 0 0 0 0 0
Zombie 0 0 2 0 1 0
plt.figure(figsize = (20,5))
sns.heatmap(ocg_crosstab_b.T, annot=True, fmt="g", cmap='viridis', square = True, norm=LogNorm())
plt.show()

By archseries¶

# Remove unlimited
ocg_crosstab_c = pd.crosstab(exploded_archseries['Archseries'].where(exploded_archseries['OCG status']!='Unlimited'), exploded_archseries['OCG status'], margins = True)
ocg_crosstab_c
OCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited All
Archseries
-Eyes Dragon 1 0 0 0 1 0 2
A-to-Z 0 0 0 1 0 0 1
Abyss- 0 0 0 0 1 0 1
Adventurer Token (series) 0 0 0 2 0 0 2
Amazoness 1 0 0 0 0 0 1
... ... ... ... ... ... ... ...
Zombie counterpart 0 0 1 0 0 0 1
Zoodiac 2 0 0 2 0 0 4
roid 0 0 0 1 0 0 1
tellarknight 1 0 0 0 0 0 1
All 72 33 27 58 50 16 256

132 rows × 7 columns

TCG vs. OCG status¶

cg_crosstab = pd.crosstab(formatted_full_df['OCG status'],formatted_full_df['TCG status'], dropna=False, margins = False)
cg_crosstab
TCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited Unlimited
OCG status
Forbidden 72 0 0 6 0 0 11
Illegal 0 26 0 0 0 0 0
Legal 0 0 20 0 0 0 0
Limited 7 0 0 33 0 3 22
Not yet released 0 0 0 0 0 0 39
Semi-Limited 1 0 0 5 0 3 10
Unlimited 19 0 0 37 1 3 11205
plt.figure(figsize = (10,8))
sns.heatmap(cg_crosstab, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

HTML export¶

! jupyter nbconvert Cards.ipynb --to=HTML --TemplateExporter.exclude_input_prompt=True --TemplateExporter.exclude_output_prompt=True

Searches¶

formatted_full_df.loc[formatted_full_df['OCG status'] == 'Not yet released'].loc[formatted_full_df['TCG status'] == 'Not yet released']
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK ... Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date

0 rows × 21 columns